﻿using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;

namespace FrontDisplay
{
    public abstract class AnimatedBackground : IAnimatedBackground
    {
        private readonly Int32Rect _rect;
        private readonly int _bytesPerPixel;
        private readonly int _stride;
        private readonly int _arraySize;
        private readonly byte[] _colorArray;
        private readonly DispatcherTimer _timer;
        private readonly int[,] _palette = new int[256, 3];

        protected ImageBrush InternalBrush { get; set; }
        protected WriteableBitmap Bitmap { get; set; }

        protected int[,] Buffer { get; set; }

        private readonly int _imageWidth;
        private readonly int _imageHeight;

        protected int ImageWidth
        {
            get { return _imageWidth; }
        }

        protected int ImageHeight
        {
            get { return _imageHeight; }
        }

        protected AnimatedBackground(int imageWidth, int imageHeight)
        {
            _imageWidth = imageWidth;
            _imageHeight = imageHeight;

            Bitmap = new WriteableBitmap(imageWidth, imageHeight, 96, 96, PixelFormats.Bgra32, null);
            _rect = new Int32Rect(0, 0, Bitmap.PixelWidth, Bitmap.PixelHeight);
            _bytesPerPixel = (Bitmap.Format.BitsPerPixel + 7) / 8;
            _stride = Bitmap.PixelWidth * _bytesPerPixel;
            _arraySize = _stride * Bitmap.PixelHeight;
            _colorArray = new byte[_arraySize];

            _timer = new DispatcherTimer();
            _timer.Tick += AnimationTimerTick;
            _timer.Interval = TimeSpan.FromMilliseconds(1000 / 30.0);

            InternalBrush = new ImageBrush { ImageSource = Bitmap };
        }

        private void AnimationTimerTick(object sender, EventArgs e)
        {
            //((RotateTransform)InternalBrush.RelativeTransform).Angle += 1;
            //Bitmap.Lock();

            UpdateBuffer();

            int c = 0;
            for (int a = 0; a < _imageHeight; a++)
            {
                for (int b = 0; b < _imageWidth; b++)
                {
                    _colorArray[c] = (byte)_palette[Buffer[a, b], 2];
                    c++;
                    _colorArray[c] = (byte)_palette[Buffer[a, b], 1];
                    c++;
                    _colorArray[c] = (byte)_palette[Buffer[a, b], 0];
                    c++;
                    _colorArray[c] = 255;
                    c++;
                }
            }

            //Marshal.Copy(_colorArray, 0, Bitmap.BackBuffer, _colorArray.Length);
            //Bitmap.AddDirtyRect(_rect);

            //Update writeable bitmap with the colorArray to the image.
            Bitmap.WritePixels(_rect, _colorArray, _stride, 0);

            //Bitmap.Unlock();
        }

        protected void SetPaletteColors(Color startColor, Color endColor, int start, int end)
        {
            int len = end - start;
            int r = startColor.R - endColor.R;
            int g = startColor.G - endColor.G;
            int b = startColor.B - endColor.B;

            for (int i = 0; i < len; i++)
            {
                _palette[(i + start), 0] = startColor.R - (i * r / len);
                _palette[(i + start), 1] = startColor.G - (i * g / len);
                _palette[(i + start), 2] = startColor.B - (i * b / len);
            }
        }


        protected abstract void UpdateBuffer();

        public abstract string Name { get; }

        public Brush Brush
        {
            get { return InternalBrush; }
        }

        public abstract void UpdateColors();

        public void Start()
        {
            UpdateColors();

            _timer.Start();
        }

        public void Stop()
        {
            _timer.Stop();
        }
    }
}
